package cn.itcast.hotel;

import cn.itcast.hotel.pojo.HotelDoc;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Map;

public class EsSearchDemo {
    //全局
    private RestHighLevelClient client;

    //初始化RestHighLevelClient
    @BeforeEach
    public void setup() {
        this.client = new RestHighLevelClient(RestClient.builder(
                HttpHost.create("http://180.76.145.80:9200")
        ));
    }

    /**
     * 关闭流
     * @throws IOException
     */
    @AfterEach
    void tearDown() throws IOException {
        this.client.close();
    }

    /**
     * 查询全部
     */
    @Test
    public void searchTest() throws IOException {
        //做什么样的操作就创建对应的请求对象
        SearchRequest request =new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        //构造条件
        source.query(QueryBuilders.matchAllQuery());
        //调用客户端执行对应的请求
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析响应结果
        SearchHits hits = response.getHits();
        System.out.println(hits.getTotalHits().value);
        //获得文档内容
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);
            System.out.println(hotelDoc);
        }
    }

    /**
     * mach查询
     * @throws IOException
     */
    @Test
    public void mach() throws IOException {
        SearchRequest request =new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        SearchSourceBuilder query = source.query(QueryBuilders.matchQuery("name","如家外滩"));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        SearchHits hits = response.getHits();
        System.out.println(hits.getTotalHits().value);
        //获得文档内容
        SearchHit[] searchHits = hits.getHits();
        for (SearchHit searchHit : searchHits) {
            String sourceAsString = searchHit.getSourceAsString();
            HotelDoc hotelDoc = JSON.parseObject(sourceAsString, HotelDoc.class);
            System.out.println(hotelDoc);
        }
    }
    @Test
    public void hight() throws IOException {
        SearchRequest request =new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        SearchSourceBuilder query = source.query(QueryBuilders.matchQuery("name","如家外滩"));
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name");
        highlightBuilder.preTags("<span>");
        highlightBuilder.postTags("</span>");
        source.highlighter(highlightBuilder);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /**
     * 价格范围1000-3000
     * @throws IOException
     */
    @Test
    public void rangs() throws IOException {
        SearchRequest request =new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        SearchSourceBuilder query = source.query(QueryBuilders.rangeQuery("price").gte("1000").lte("3000"));
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /**
     * 布尔查询
     * @throws IOException
     */
    @Test
    public void bool() throws IOException {
        SearchRequest request =new SearchRequest("hotel");
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //添加match
        MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery("name", "上海外滩");
        boolQuery.must(matchQueryBuilder);
        //添加range
        RangeQueryBuilder price = QueryBuilders.rangeQuery("price").lte(250);
        boolQuery.filter(price);
        //添加term
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("brand", "万怡");
        boolQuery.mustNot(termQueryBuilder);
        //添加到query
        request.source().query(boolQuery);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }

    /**
     * 排序查询
     * @throws IOException
     */
    @Test
    public void  sortAndPage() throws IOException{
        SearchRequest request =new SearchRequest("hotel");
        SearchSourceBuilder source = request.source();
        source.sort("score", SortOrder.ASC);
        source.sort("price",SortOrder.DESC);
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        handleResponse(response);
    }


    /**
     * 解析响应结果
     * @param response
     */
    private void handleResponse(SearchResponse response) {
        // 4.解析响应
        SearchHits searchHits = response.getHits();
        // 4.1.获取总条数
        long total = searchHits.getTotalHits().value;
        System.out.println("共搜索到" + total + "条数据");
        // 4.2.文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3.遍历
        for (SearchHit hit : hits) {
            // 获取文档source
            String json = hit.getSourceAsString();
            // 反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            //高亮处理
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if(!CollectionUtils.isEmpty(highlightFields)){
                // 根据字段名获取高亮结果
                HighlightField highlightField = highlightFields.get("name");
                if(highlightField !=null){
                    //获取高亮值
                    String name = highlightField.getFragments()[0].string();
                    //覆盖非高亮结果
                    hotelDoc.setName(name);
                }

            }
            System.out.println("hotelDoc = " + hotelDoc);
        }
    }
}

